package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.domain.entity.PaasProcessDataEntity;
import com.xbongbong.paas.domain.entity.PaasProcessNodeTaskEntity;
import com.xbongbong.paas.domain.entity.PaasProcessTaskEntity;
import com.xbongbong.paas.domain.entity.ext.OptionalRangeEntity;
import com.xbongbong.paas.domain.entity.ext.PaasProcessNodeTaskEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasProcessTemplateEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasProcessTemplateNodeEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.NodeTypeEnum;
import com.xbongbong.paas.enums.OptionalRangeEnum;
import com.xbongbong.paas.enums.ProcessTypeEnum;
import com.xbongbong.paas.enums.TaskTypeEnum;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.model.PaasProcessDataModel;
import com.xbongbong.paas.model.PaasProcessNodeTaskModel;
import com.xbongbong.paas.model.PaasProcessTaskModel;
import com.xbongbong.paas.model.PaasProcessTemplateModel;
import com.xbongbong.paas.model.PaasProcessTemplateNodeModel;
import com.xbongbong.paas.pojo.dto.ProcessDataAddDTO;
import com.xbongbong.paas.pojo.dto.ProcessNodeTaskAddBatchDTO;
import com.xbongbong.paas.pojo.dto.ProcessNodeTaskAddDTO;
import com.xbongbong.paas.pojo.dto.ProcessNodeTaskUpdateDTO;
import com.xbongbong.paas.pojo.dto.StartProcessDTO;
import com.xbongbong.paas.pojo.vo.ProcessNodeTaskUpdateVO;
import com.xbongbong.paas.pojo.vo.StartProcessVO;
import com.xbongbong.paas.service.PaasProcessNodeTaskOperateService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.parent.help.PushMessageHelp;
import com.xbongbong.pro.enums.errorcodes.ApprovalErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.BuinessDefaultErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.workrecord.enums.WorkrecordResultEnum;
import com.xbongbong.pro.message.constant.ProcessPushConstant;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.process.pojo.dto.WorkrecordUpdateTaskDTO;
import com.xbongbong.pro.rabbitmq.producer.BaseProducer;
import com.xbongbong.pro.service.dingtalk.WorkflowDingtalkService;
import com.xbongbong.process.ProcessOperateHelp;
import com.xbongbong.process.ding.DingtalkWorkrecordService;
import com.xbongbong.process.operate.PaasProcessOperateService;
import com.xbongbong.process.task.NodeTaskListUpdateProcessServiceImpl;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ext.WorkOrderFormEntityExt;
import com.xbongbong.saas.enums.SignTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.model.WorkOrderFormModel;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.DepartmentModel;
import com.xbongbong.sys.model.UserModel;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author: wufeng
 * @date: 2018/8/22 17:07
 * @desrcption:
 */
@Service(value = "paasProcessNodeOperateService")
public class PaasProcessNodeTaskOperateServiceImpl implements PaasProcessNodeTaskOperateService {

    private static final Logger LOG = LoggerFactory.getLogger(PaasProcessNodeTaskOperateServiceImpl.class);

    @Resource
    private PaasProcessTemplateNodeModel processTemplateNodeModel;
    @Resource
    private PaasProcessNodeTaskModel paasProcessNodeTaskModel;
    @Resource
    private PaasProcessDataModel paasProcessDataModel;
    @Resource
    private PaasProcessOperateService paasProcessOperateService;
    @Resource
    private NodeTaskListUpdateProcessServiceImpl nodeTaskListUpdateProcessService;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private UserModel userModel;
    @Resource
    private PushMessageHelp pushMessageHelp;
    @Resource
    private WorkOrderFormModel workOrderFormModel;
    @Resource
    private DepartmentModel departmentModel;
    @Resource
    private PaasProcessTaskModel paasProcessTaskModel;
    @Resource
    private DingtalkWorkrecordService dingtalkWorkrecordService;
    @Resource
    private WorkflowDingtalkService workflowDingtalkService;
    @Resource
    private PaasProcessTemplateModel paasProcessTemplateModel;
    @Resource
    private ProcessOperateHelp processOperateHelp;

    @Override
    public ProcessNodeTaskUpdateVO dingCommit(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        LOG.warn("更新钉钉待办任务,开始处理数据,公司id:"+processNodeTaskUpdateDTO.getCorpid());
        ProcessNodeTaskUpdateVO processNodeTaskUpdateVO = new ProcessNodeTaskUpdateVO();
        String corpid = processNodeTaskUpdateDTO.getCorpid();
        try {
            BeanUtils.copyProperties(processNodeTaskUpdateDTO, processNodeTaskUpdateVO);
            // 查询任务所在当前节点信息
            PaasProcessTemplateNodeEntityExt processTemplateNodeEntity = processNodeTaskUpdateDTO.getProcessTemplateNode();

            // start 钉钉工作台 更新单个节点审批状态
            PaasProcessNodeTaskEntity processNodeTaskEntity = processNodeTaskUpdateDTO.getPaasProcessNodeTaskEntity();
            String workrecordTaskId = processNodeTaskEntity.getDingtalkWorkrecordTaskId();
            PaasProcessTaskEntity paasProcessTaskEntity = paasProcessTaskModel.getByKey(processNodeTaskUpdateDTO.getProcessTaskId().intValue(), corpid);
            String dingtalkProcessInstanceId = paasProcessTaskEntity.getDingtalkProcessInstanceId();
            if (StringUtil.isNotEmpty(workrecordTaskId)) {
                WorkrecordUpdateTaskDTO workrecordUpdateTaskDTO = new WorkrecordUpdateTaskDTO();
                workrecordUpdateTaskDTO.setCorpid(corpid);
                workrecordUpdateTaskDTO.setDingtalkInstanceId(dingtalkProcessInstanceId);
                workrecordUpdateTaskDTO.setDingtalkTaskId(workrecordTaskId);
                LOG.warn("更新钉钉待办任务,结束处理数据,公司id:"+processNodeTaskUpdateDTO.getCorpid());
                workflowDingtalkService.updateDingtalkTask(workrecordUpdateTaskDTO, WorkrecordResultEnum.AGREE);
            }
            // end

            // 会签逻辑处理 started
            if (processTemplateNodeEntity.getSignType().equals(SignTypeEnum.COUNTERSIGN.getValue())) {
                Map<String, Object> map = BeanUtil.convertBean2Map(processNodeTaskUpdateDTO, true);
                map.put("templateNodeId", processNodeTaskUpdateDTO.getProcessTemplateNode().getId());
                map.put("taskId", processNodeTaskUpdateDTO.getProcessTaskId());
                map.put("taskType", TaskTypeEnum.UNTREATED.getType());
                Integer count = paasProcessNodeTaskModel.getEntitysCount(map);
                if (count > 0) {
                    processOperateHelp.updateProcessType(processNodeTaskUpdateDTO);
                    // 会签时，后续需要用到这个flowStatus，而假如当前还会存在未审批完的任务，就表明该审批还在审批中；
                    processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.IN_APPROVAL.getType());
                    processOperateHelp.updateProcessData(processNodeTaskUpdateDTO);
                    return processNodeTaskUpdateVO;
                }
            }
            // 会签逻辑处理 end
            // 或签将其他任务的taskType改为其他人已处理
            orSignOperate(processNodeTaskUpdateDTO);
            // TODO 将此节点的抄送任务更新为抄送状态
            ccOperate(processNodeTaskUpdateDTO);
            // 提交到下一节点
            ProcessDataAddDTO processDataAddDTO = new ProcessDataAddDTO();
            BeanUtil.copyProperties(processNodeTaskUpdateDTO, processDataAddDTO);
            processDataAddDTO.setData(processNodeTaskUpdateDTO.getDataList());
            processDataAddDTO.setTemplateId(processTemplateNodeEntity.getTemplateId());
            processDataAddDTO.setCreatorId(paasProcessTaskEntity.getCreatorId());
            processDataAddDTO.setTaskId(processNodeTaskUpdateDTO.getProcessTaskId());
            processDataAddDTO.setSaasNeedRedundantAttrPoJo(processNodeTaskUpdateDTO.getSaasNeedRedundantAttrPoJo());
            StartProcessVO startProcessVO = paasProcessOperateService.deliverToNextNode(processTemplateNodeEntity, processDataAddDTO);

            // 更新流程状态和流程负责人
            if (Objects.equals(startProcessVO.getNoApprovalRequired(), 1)) {
                // 如果目标节点为结束节点，则流程通过
                processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.PASS.getType());
                // start 钉钉工作台 更新整个流程的审批状态
                if (StringUtil.isNotEmpty(dingtalkProcessInstanceId)) {
                    workflowDingtalkService.updateDingtalkInstance(corpid, dingtalkProcessInstanceId, WorkrecordResultEnum.AGREE);
                }
            } else if (Objects.equals(startProcessVO.getNoApprovalRequired(), BasicConstant.TWO)) {
                processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.REJECT.getType());
            } else {
                // 将流程节点置为进行中
                processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.IN_APPROVAL.getType());
            }
            processOperateHelp.updateProcessType(processNodeTaskUpdateDTO);
            processOperateHelp.updateProcessData(processNodeTaskUpdateDTO);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("processNodeTaskOperate数据库流程提交操作出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return processNodeTaskUpdateVO;
    }

    private void ccOperate(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        Long taskId = processNodeTaskUpdateDTO.getProcessTaskId();
        String corpid = processNodeTaskUpdateDTO.getCorpid();
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put("del", 0);
        params.put("corpid", corpid);
        params.put("taskType", TaskTypeEnum.WAIT_CC.getType());
        params.put("taskId", taskId);
        params.put("templateNodeId", processNodeTaskUpdateDTO.getProcessTemplateNode().getId());
        List<PaasProcessNodeTaskEntityExt> nodeTaskList = paasProcessNodeTaskModel.findEntitys(params);
        if (nodeTaskList == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
        }
        List<PaasProcessNodeTaskEntity> updateNodeTaskList = new ArrayList<>();
        nodeTaskList.forEach((item) -> {
            long now = DateUtil.getInt();
            PaasProcessNodeTaskEntity paasProcessNodeTaskEntity = new PaasProcessNodeTaskEntity();
            paasProcessNodeTaskEntity.setId(item.getId());
            paasProcessNodeTaskEntity.setTaskType(TaskTypeEnum.CC.getType());
            paasProcessNodeTaskEntity.setUpdateTime(now);
            updateNodeTaskList.add(paasProcessNodeTaskEntity);

        });
        if (!updateNodeTaskList.isEmpty()) {
            paasProcessNodeTaskModel.updateBatch(updateNodeTaskList, corpid);
            // 待抄送的人员抄送消息的抄送
            PaasProcessTemplateNodeEntityExt processTemplateNodeEntity = processNodeTaskUpdateDTO.getProcessTemplateNode();
            Long appId = processTemplateNodeEntity.getAppId();
            Long menuId = processTemplateNodeEntity.getMenuId();
            Long formId = processTemplateNodeEntity.getFormId();
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("del", 0);
            List<UserEntity> userList = userModel.findEntitys(param);
            Map<String, UserEntity> userMap = new HashMap<>(userList.size());
            userList.forEach((item) -> userMap.put(item.getUserId(), item));
            // 获取部门容器
            param.remove(ParameterConstant.COLUMNS);
            List<DepartmentEntity> departmentList = departmentModel.findEntitys(param);
            Map<String, DepartmentEntity> departmentMap = new HashMap<>(departmentList.size());
            departmentList.forEach((departmentItem) -> departmentMap.put(departmentItem.getId().toString(), departmentItem));
            PaasProcessDataEntity paasProcessDataEntity = paasProcessDataModel.getByTaskId(taskId, corpid);
            String content = pushMessageHelp.getMessageContent(paasProcessDataEntity, userMap, departmentMap, processNodeTaskUpdateDTO);
            String formName;
            if (Objects.equals(paasProcessDataEntity.getBusinessType(), XbbRefTypeEnum.WORK_ORDER.getCode())) {
                WorkOrderFormEntityExt workOrderFormEntityExt = workOrderFormModel.getByKey(formId, corpid);
                formName = workOrderFormEntityExt.getName();
            } else {
                PaasFormEntity paasFormEntity = paasFormModel.getByKey(paasProcessDataEntity.getFormId(), corpid);
                formName = paasFormEntity.getName();
            }
            PushTypeEnum pushTypeEnum = PushTypeEnum.APPROVAL_CARBON_COPY_PUSH;
            Long dataId = paasProcessDataEntity.getId();
            UserEntity creatorUser = userModel.getByKeyIngoreDel(paasProcessDataEntity.getCreatorId(), corpid);
            for (PaasProcessNodeTaskEntityExt paasProcessNodeTaskEntityExt : nodeTaskList) {
                PushRefTypePojo.Options options = new PushRefTypePojo.Options(appId, menuId, formId, Collections.singletonList(dataId), paasProcessDataEntity.getSaasMark(), paasProcessDataEntity.getBusinessType(), taskId, paasProcessNodeTaskEntityExt.getId(), ProcessTypeEnum.CC.getValue());
                MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, Collections.singletonList(paasProcessNodeTaskEntityExt.getUserId()), Collections.singletonList(taskId), 0, DateTimeUtil.getInt(), I18nMessageUtil.getMessage(ProcessPushConstant.PROCESS_CARBON_COPY_TITLE), String.format(I18nMessageUtil.getMessage(ProcessPushConstant.PROCESS_CARBON_COPY_CONTENT), creatorUser.getName(), formName, content), null, options);
                baseProducer.sendMessage(pushTypeEnum, messageRabbitMqDTO);
            }
        }
    }

    /**
     * 或签操作
     *
     * @param processNodeTaskUpdateDTO
     * @throws XbbException
     */
    private void orSignOperate(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        try {
            if (processNodeTaskUpdateDTO.getProcessTemplateNode().getSignType().equals(SignTypeEnum.ORSIGN.getValue())) {
                otherNodeTaskOperate(processNodeTaskUpdateDTO);
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("processNodeTaskOperate或签操作将其他节点任务修改出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    /**
     * 回退时，不管节点是会签还是或签，都将其他人的状态改成其他人同意
     *
     * @param processNodeTaskUpdateDTO
     * @throws XbbException
     */
    private void backOperate(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        try {
            otherNodeTaskOperate(processNodeTaskUpdateDTO);
            deleteWaitCCTask(processNodeTaskUpdateDTO);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("processNodeTaskOperate回退操作将其他节点任务修改出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    private void otherNodeTaskOperate(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        try {
            String corpid = processNodeTaskUpdateDTO.getCorpid();
            Map<String, Object> params = new HashMap<>();
            params.put(StringConstant.CORPID, corpid);
            params.put(StringConstant.FORM_ID, processNodeTaskUpdateDTO.getFormId());
            params.put(StringConstant.TASK_ID, processNodeTaskUpdateDTO.getProcessTaskId());
            params.put("templateNodeId", processNodeTaskUpdateDTO.getProcessTemplateNode().getId());
            List<PaasProcessNodeTaskEntityExt> nodeTaskList = paasProcessNodeTaskModel.findEntitys(params);
            if (nodeTaskList == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
            }
            List<PaasProcessNodeTaskEntity> updateNodeTaskList = new ArrayList<>();
            nodeTaskList.forEach((item) -> {
                if (!processNodeTaskUpdateDTO.getUserId().equals(item.getUserId()) && item.getTaskType().equals(TaskTypeEnum.UNTREATED.getType())) {
                    long now = DateUtil.getInt();
                    PaasProcessNodeTaskEntity paasProcessNodeTaskEntity = new PaasProcessNodeTaskEntity();
                    paasProcessNodeTaskEntity.setId(item.getId());
                    paasProcessNodeTaskEntity.setTaskType(TaskTypeEnum.OTHER_COMMIT.getType());
                    paasProcessNodeTaskEntity.setUpdateTime(now);
                    updateNodeTaskList.add(paasProcessNodeTaskEntity);
                }
            });

            // start 钉钉工作台 取消其他节点的审批状态
            PaasProcessTaskEntity paasProcessTaskEntity = paasProcessTaskModel.getByKey(processNodeTaskUpdateDTO.getProcessTaskId().intValue(), corpid);
            String dingtalkProcessInstanceId = paasProcessTaskEntity.getDingtalkProcessInstanceId();
            if (StringUtil.isEmpty(dingtalkProcessInstanceId)) {
                WorkrecordUpdateTaskDTO workrecordUpdateTaskDTO = new WorkrecordUpdateTaskDTO();
                workrecordUpdateTaskDTO.setCorpid(corpid);
                workrecordUpdateTaskDTO.setDingtalkInstanceId(dingtalkProcessInstanceId);
                workrecordUpdateTaskDTO.setDingtalkActivityId(nodeTaskList.get(0).getDingtalkWorkrecordActivityId());
                List<String> activityIds = nodeTaskList.stream().map(PaasProcessNodeTaskEntityExt::getDingtalkWorkrecordActivityId).distinct().collect(Collectors.toList());
                workrecordUpdateTaskDTO.setDingtalkActivityIds(activityIds);
                workflowDingtalkService.batchCancelDingtalkTask(workrecordUpdateTaskDTO);
            }
            // end

            if (!updateNodeTaskList.isEmpty()) {
                paasProcessNodeTaskModel.updateBatch(updateNodeTaskList, processNodeTaskUpdateDTO.getCorpid());
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("processNodeTaskOperate将其他节点任务修改出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    private void deleteWaitCCTask(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        try {
            Map<String, Object> params = BeanUtil.convertBean2Map(processNodeTaskUpdateDTO, true);
            params.put("del", 0);
            params.put("templateNodeId", processNodeTaskUpdateDTO.getProcessTemplateNode().getId());
            params.put("taskId", processNodeTaskUpdateDTO.getProcessTaskId());
            params.put("taskType", TaskTypeEnum.WAIT_CC.getType());
            List<PaasProcessNodeTaskEntityExt> nodeTaskList = paasProcessNodeTaskModel.findEntitys(params);
            List<PaasProcessNodeTaskEntity> delNodeTaskList = new ArrayList<>();
            nodeTaskList.forEach((item) -> {
                long now = DateUtil.getInt();
                PaasProcessNodeTaskEntity paasProcessNodeTaskEntity = new PaasProcessNodeTaskEntity();
                paasProcessNodeTaskEntity.setId(item.getId());
                paasProcessNodeTaskEntity.setDel(1);
                paasProcessNodeTaskEntity.setUpdateTime(now);
                delNodeTaskList.add(paasProcessNodeTaskEntity);
            });
            if (!delNodeTaskList.isEmpty()) {
                paasProcessNodeTaskModel.updateBatch(delNodeTaskList, processNodeTaskUpdateDTO.getCorpid());
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("processNodeTaskOperate将其他节点任务修改出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public ProcessNodeTaskUpdateVO storage(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        ProcessNodeTaskUpdateVO processNodeTaskUpdateVO = new ProcessNodeTaskUpdateVO();
        try {
            processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.IN_APPROVAL.getType());
            processOperateHelp.updateProcessType(processNodeTaskUpdateDTO);
            processOperateHelp.updateProcessData(processNodeTaskUpdateDTO);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("PaasProcessTask流程暂存操作出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return processNodeTaskUpdateVO;
    }


    @Override
    public ProcessNodeTaskUpdateVO transfer(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        ProcessNodeTaskUpdateVO processNodeTaskUpdateVO = new ProcessNodeTaskUpdateVO();
        String corpid = processNodeTaskUpdateDTO.getCorpid();
        try {
            String transferUserId = processNodeTaskUpdateDTO.getTransferUserId();
            if (StringUtil.isEmpty(transferUserId)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.TRANSFER_USER_NOT_EXIST);
            }
            if (processNodeTaskUpdateDTO.getUserId().equals(transferUserId)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.TRANSFER_USER_NOT_TO_ME);
            }

            // start 钉钉工作台 更新其他审批人的审批任务
            PaasProcessNodeTaskEntity processNodeTaskEntity = processNodeTaskUpdateDTO.getPaasProcessNodeTaskEntity();
            String workrecordTaskId = processNodeTaskEntity.getDingtalkWorkrecordTaskId();
            PaasProcessTaskEntity paasProcessTaskEntity = paasProcessTaskModel.getByKey(processNodeTaskUpdateDTO.getProcessTaskId().intValue(), corpid);
            if (StringUtil.isNotEmpty(workrecordTaskId)) {
                WorkrecordUpdateTaskDTO workrecordUpdateTaskDTO = new WorkrecordUpdateTaskDTO();
                workrecordUpdateTaskDTO.setCorpid(corpid);
                workrecordUpdateTaskDTO.setDingtalkInstanceId(paasProcessTaskEntity.getDingtalkProcessInstanceId());
                workrecordUpdateTaskDTO.setDingtalkTaskId(workrecordTaskId);
                workflowDingtalkService.updateDingtalkTask(workrecordUpdateTaskDTO, WorkrecordResultEnum.CANCELED);
            }
            // end

            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("corpid", processNodeTaskUpdateDTO.getCorpid());
            params.put("taskId", processNodeTaskUpdateDTO.getProcessTaskId());
            params.put("userId", transferUserId);
            params.put("templateNodeId", processNodeTaskUpdateDTO.getProcessTemplateNode().getId());
            params.put("taskType", TaskTypeEnum.UNTREATED.getType());
            params.put("del", 0);
            Integer count = paasProcessNodeTaskModel.getEntitysCount(params);
            if (count > 0) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.TRANSFER_USER_NOT_TO_SAME);
            }

            PaasProcessTemplateNodeEntityExt processTemplateNodeEntity = processNodeTaskUpdateDTO.getProcessTemplateNode();
            // 为转交人创建任务
            List<OptionalRangeEntity> optionalRangeList = new ArrayList<>();
            OptionalRangeEntity optionalRangeEntity = new OptionalRangeEntity();
            optionalRangeEntity.setProperty(OptionalRangeEnum.USER.getValue());
            optionalRangeEntity.setId(transferUserId);
            optionalRangeList.add(optionalRangeEntity);
            List<ProcessNodeTaskAddDTO> userNodeTaskList = nodeTaskListUpdateProcessService.getNodeTaskList(optionalRangeList, processNodeTaskUpdateDTO, processTemplateNodeEntity, TaskTypeEnum.UNTREATED.getType());
            if (userNodeTaskList.isEmpty()) {
                // 转交人为空，改为系统转交
                ProcessNodeTaskAddDTO nodeTaskAddDTO = new ProcessNodeTaskAddDTO();
                BeanUtil.copyProperties(processNodeTaskUpdateDTO, nodeTaskAddDTO);
                nodeTaskAddDTO.setTemplateNodeId(processTemplateNodeEntity.getId());
                nodeTaskAddDTO.setNodeType(processTemplateNodeEntity.getType());
                nodeTaskAddDTO.setUserId(PaasConstant.SYS_USER_ID);
                nodeTaskAddDTO.setTaskId(processNodeTaskUpdateDTO.getProcessTaskId());
                nodeTaskAddDTO.setSignType(SignTypeEnum.ORSIGN.getValue());
                nodeTaskAddDTO.setCreatorId(processNodeTaskUpdateDTO.getUserId());
                nodeTaskAddDTO.setTaskType(TaskTypeEnum.SYSTEM_COMMIT.getType());
                userNodeTaskList.add(nodeTaskAddDTO);
            }
            ProcessNodeTaskAddBatchDTO processNodeTaskAddBatchDTO = new ProcessNodeTaskAddBatchDTO();
            BeanUtil.copyProperties(processNodeTaskUpdateDTO, processNodeTaskAddBatchDTO);
            processNodeTaskAddBatchDTO.setUserNodeTaskList(userNodeTaskList);
            processNodeTaskAddBatchDTO.setLastNodeId(processNodeTaskUpdateDTO.getPaasProcessNodeTaskEntity().getLastNodeId());
            processOperateHelp.createTask(processNodeTaskAddBatchDTO);

            // 更新流程状态和流程负责人
            processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.IN_APPROVAL.getType());
            processOperateHelp.updateProcessType(processNodeTaskUpdateDTO);
            processOperateHelp.updateProcessData(processNodeTaskUpdateDTO);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("PaasProcessTask数据库流程转交操作出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return processNodeTaskUpdateVO;
    }


    @Override
    public ProcessNodeTaskUpdateVO dingBack(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        ProcessNodeTaskUpdateVO processNodeTaskUpdateVO = new ProcessNodeTaskUpdateVO();
        try {
            // 任务id
            Long taskId = processNodeTaskUpdateDTO.getProcessTaskId();
            Long templateNodeId = processNodeTaskUpdateDTO.getPaasProcessNodeTaskEntity().getTemplateNodeId();
            Long backTemplateNodeId = null;
            PaasProcessNodeTaskEntityExt backNodeTask = null;
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("corpid", processNodeTaskUpdateDTO.getCorpid());
            params.put("taskId", taskId);
            params.put("del", 0);
            params.put("orderByStr"," id " + SortOrder.DESC);
            List<PaasProcessNodeTaskEntityExt> nodeTaskList = paasProcessNodeTaskModel.findEntitys(params);
            // 之前的已经回退过的节点 之前有连续回退的操作会有bug，所以需要过滤回退的节点
            Set<Long> haveBackNode = new HashSet<>();
            for (PaasProcessNodeTaskEntityExt nodeTaskEntityExt : nodeTaskList) {
                Long nodeId = nodeTaskEntityExt.getTemplateNodeId();
                if (!Objects.equals(nodeId, templateNodeId) && Objects.equals(TaskTypeEnum.BACK.getType(), nodeTaskEntityExt.getTaskType())) {
                    haveBackNode.add(nodeId);
                }
            }
            for (PaasProcessNodeTaskEntityExt paasProcessNodeTaskEntityExt : nodeTaskList) {
                Long nodeId = paasProcessNodeTaskEntityExt.getTemplateNodeId();
                if (!Objects.equals(nodeId, templateNodeId) && !haveBackNode.contains(nodeId)) {
                    backTemplateNodeId = paasProcessNodeTaskEntityExt.getTemplateNodeId();
                    backNodeTask = paasProcessNodeTaskEntityExt;
                    break;
                }
            }
            if (backNodeTask == null || backTemplateNodeId == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.NOT_FOUND_LAST_NODE);
            }
            if (Objects.equals(backNodeTask.getNodeType(), NodeTypeEnum.START_PROCESS_NODE.getNodeType())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.NOT_ALLOWED_TO_BACK);
            } else if (Objects.equals(backNodeTask.getNodeType(), NodeTypeEnum.CC_PROCESS_NODE.getNodeType())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.NOT_ALLOWED_TO_BACK_CC);
            }
            PaasProcessTemplateNodeEntityExt backTemplateNode = processTemplateNodeModel.getByKey(backTemplateNodeId.intValue(), processNodeTaskUpdateDTO.getCorpid());

            backOperate(processNodeTaskUpdateDTO);
            // 获取当前节点数据
            PaasProcessDataEntity  processDataEntity= paasProcessDataModel.getByTaskId(processNodeTaskUpdateDTO.getProcessTaskId(), processNodeTaskUpdateDTO.getCorpid());
            JSONObject dataList = JSON.parseObject(processDataEntity.getData());
            processNodeTaskUpdateDTO.setDataList(dataList);
            // 检索出当前任务回退节点的上一节点
            params.clear();
            params.put("taskId", processNodeTaskUpdateDTO.getProcessTaskId());
            params.put("templateNodeId", backTemplateNode.getId());
            params.put("del", DelEnum.NORMAL.getDel());
            params.put("corpid", processNodeTaskUpdateDTO.getCorpid());
            List<PaasProcessNodeTaskEntityExt> backNodeTaskList = paasProcessNodeTaskModel.findEntitys(params);
            if (backNodeTaskList == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
            }
            Long lastNodeId = nodeTaskList.get(0).getLastNodeId();
            // 流程任务
            List<OptionalRangeEntity> mainUserList = backTemplateNode.getMainUserList();
            List<ProcessNodeTaskAddDTO> userNodeTaskList = nodeTaskListUpdateProcessService.getNodeTaskList(mainUserList, processNodeTaskUpdateDTO, backTemplateNode, TaskTypeEnum.UNTREATED.getType());


            if(userNodeTaskList.isEmpty()) {
                throw new XbbException(BuinessDefaultErrorCodeEnum.API_ERROR_200027);
            }

            ProcessNodeTaskAddBatchDTO processNodeTaskAddBatchDTO = new ProcessNodeTaskAddBatchDTO();
            BeanUtil.copyProperties(processNodeTaskUpdateDTO, processNodeTaskAddBatchDTO);
            processNodeTaskAddBatchDTO.setUserNodeTaskList(userNodeTaskList);
            processNodeTaskAddBatchDTO.setLastNodeId(lastNodeId);
            processOperateHelp.createTask(processNodeTaskAddBatchDTO);
            // 抄送任务
            List<OptionalRangeEntity> ccUserList = backTemplateNode.getCcUserList();
            if (Objects.equals(backTemplateNode.getEnableCCFlag(), 1) && !ccUserList.isEmpty()) {
                List<ProcessNodeTaskAddDTO> ccUserNodeTaskList = nodeTaskListUpdateProcessService.getNodeTaskList(ccUserList, processNodeTaskUpdateDTO, backTemplateNode, TaskTypeEnum.WAIT_CC.getType());
                processNodeTaskAddBatchDTO = new ProcessNodeTaskAddBatchDTO();
                BeanUtil.copyProperties(processNodeTaskUpdateDTO, processNodeTaskAddBatchDTO);
                processNodeTaskAddBatchDTO.setUserNodeTaskList(ccUserNodeTaskList);
                processNodeTaskAddBatchDTO.setLastNodeId(lastNodeId);
                processOperateHelp.createTask(processNodeTaskAddBatchDTO);
            }
            // 更新流程状态和流程负责人
            processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.REFUSE.getType());
            processNodeTaskUpdateDTO.setDataList(null);
            processOperateHelp.updateProcessType(processNodeTaskUpdateDTO);
            processOperateHelp.updateProcessData(processNodeTaskUpdateDTO);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("PaasProcessTask数据库流程回退操作出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

        return processNodeTaskUpdateVO;
    }

    @Override
    public ProcessNodeTaskUpdateVO revoke(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        String corpid = processNodeTaskUpdateDTO.getCorpid();
        ProcessNodeTaskUpdateVO processNodeTaskUpdateVO = new ProcessNodeTaskUpdateVO();
        try {
            Map<String, Object> params = BeanUtil.convertBean2Map(processNodeTaskUpdateDTO, true);
            // 查询全部的节点任务
            params.put("taskId", processNodeTaskUpdateDTO.getProcessTaskId());
            List<PaasProcessNodeTaskEntityExt> nodeTaskList = paasProcessNodeTaskModel.findEntitys(params);
            if (nodeTaskList == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
            }
            params.put("userId", processNodeTaskUpdateDTO.getUserId());
            params.put("orderByStr", " id DESC ");
            params.put("nodeType", NodeTypeEnum.START_PROCESS_NODE.getNodeType());
            // 获取最早的提交人提交的数据
            List<PaasProcessNodeTaskEntityExt> newNodeTaskList = paasProcessNodeTaskModel.findEntitys(params);
            if (newNodeTaskList == null || newNodeTaskList.isEmpty()) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
            }
            PaasProcessNodeTaskEntityExt newNodeTask = newNodeTaskList.get(0);
            newNodeTask.setTaskType(TaskTypeEnum.REVOKE.getType());
            newNodeTask.setRevokeUserId(processNodeTaskUpdateDTO.getUserId());
            paasProcessNodeTaskModel.update(newNodeTask);
            List<PaasProcessNodeTaskEntity> revokeList = new ArrayList<>();
            nodeTaskList.forEach((item) -> {
                if (item.getAddTime() >= newNodeTask.getAddTime() && !newNodeTask.getTemplateNodeId().equals(item.getTemplateNodeId())) {
                    PaasProcessNodeTaskEntity paasProcessNodeTaskEntity = new PaasProcessNodeTaskEntity();
                    BeanUtil.copyProperties(item, paasProcessNodeTaskEntity);
                    paasProcessNodeTaskEntity.setRevokeUserId(processNodeTaskUpdateDTO.getUserId());
                    paasProcessNodeTaskEntity.setDel(DelEnum.DELETE.getDel());
                    paasProcessNodeTaskEntity.setTaskType(TaskTypeEnum.REVOKE.getType());
                    revokeList.add(paasProcessNodeTaskEntity);
                }
            });
            if (!revokeList.isEmpty()) {
                paasProcessNodeTaskModel.updateBatch(revokeList, corpid);
            }
            processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.REVOKE.getType());

            // start 钉钉工作台 销毁审批任务实例
            PaasProcessTaskEntity paasProcessTaskEntity = paasProcessTaskModel.getByKey(processNodeTaskUpdateDTO.getProcessTaskId().intValue(), corpid);
            String dingtalkProcessInstanceId = paasProcessTaskEntity.getDingtalkProcessInstanceId();
            if (StringUtil.isNotEmpty(dingtalkProcessInstanceId)) {
                workflowDingtalkService.updateDingtalkInstance(processNodeTaskUpdateDTO.getCorpid(), dingtalkProcessInstanceId, WorkrecordResultEnum.TERMINATED);
            }

            // 撤回更新数据状态
            processOperateHelp.updateProcessType(processNodeTaskUpdateDTO);
            processOperateHelp.updateProcessData(processNodeTaskUpdateDTO);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("PaasProcessNodeTaskOperate.revoke撤回操作出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return processNodeTaskUpdateVO;
    }


    @Override
    public ProcessNodeTaskUpdateVO end(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        String corpid = processNodeTaskUpdateDTO.getCorpid();
        ProcessNodeTaskUpdateVO processNodeTaskUpdateVO = new ProcessNodeTaskUpdateVO();
        try {
            // 查询任务所在当前节点信息
            processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.REJECT.getType());
            otherNodeTaskOperate(processNodeTaskUpdateDTO);
            // start 钉钉工作台 更新整个流程的审批状态
            PaasProcessTaskEntity paasProcessTaskEntity = paasProcessTaskModel.getByKey(processNodeTaskUpdateDTO.getProcessTaskId().intValue(), corpid);
            String dingtalkProcessInstanceId = paasProcessTaskEntity.getDingtalkProcessInstanceId();
            if (StringUtil.isNotEmpty(dingtalkProcessInstanceId)) {
                workflowDingtalkService.updateDingtalkInstance(processNodeTaskUpdateDTO.getCorpid(), dingtalkProcessInstanceId, WorkrecordResultEnum.REFUSE);
            }
            // end

            deleteWaitCCTask(processNodeTaskUpdateDTO);
            processOperateHelp.updateProcessType(processNodeTaskUpdateDTO);
            processOperateHelp.updateProcessData(processNodeTaskUpdateDTO);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("PaasProcessNodeTaskOperate.end撤回操作出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return processNodeTaskUpdateVO;
    }

    @Override
    public ProcessNodeTaskUpdateVO dingAgainCommit(ProcessNodeTaskUpdateDTO processNodeTaskUpdateDTO) throws XbbException {
        String corpid = processNodeTaskUpdateDTO.getCorpid();
        ProcessNodeTaskUpdateVO processNodeTaskUpdateVO = new ProcessNodeTaskUpdateVO();
        processNodeTaskUpdateVO.setAppId(processNodeTaskUpdateDTO.getAppId());
        try {
            Long formDataId = processNodeTaskUpdateDTO.getFormDataId();
            Long templateId = processNodeTaskUpdateDTO.getProcessTemplateNode().getTemplateId();
            if (formDataId != null && formDataId > 0L) {
                throw new XbbException(ApprovalErrorCodeEnum.API_ERROR_209014, ApprovalErrorCodeEnum.API_ERROR_209014.getMsg());
            }
            // 删除时同步删除钉钉待办实例 会有覆盖实例id的情况，需要先删除钉钉实例
            PaasProcessTaskEntity paasProcessTaskEntity = paasProcessTaskModel.getByKey(processNodeTaskUpdateDTO.getProcessTaskId().intValue(), corpid);
            String dingtalkProcessInstanceId = paasProcessTaskEntity.getDingtalkProcessInstanceId();
            if (StringUtil.isNotEmpty(dingtalkProcessInstanceId)) {
                workflowDingtalkService.updateDingtalkInstance(paasProcessTaskEntity.getCorpid(), paasProcessTaskEntity.getDingtalkProcessInstanceId(), WorkrecordResultEnum.TERMINATED);
            }
            // 重新生成节点任务
            StartProcessDTO startProcessDTO = new StartProcessDTO();
            BeanUtil.copyProperties(processNodeTaskUpdateDTO, startProcessDTO);
            startProcessDTO.setData(processNodeTaskUpdateDTO.getDataList());
            startProcessDTO.setCreatorId(processNodeTaskUpdateDTO.getUserId());
            // 查找开始节点
            Map<String, Object> params = BeanUtil.convertBean2Map(startProcessDTO, true);
            params.put("enable", 1);
            params.remove("type");
            List<PaasProcessTemplateEntityExt> paasProcessTemplateList = paasProcessTemplateModel.list(params);
            if (paasProcessTemplateList.isEmpty()) {
                startProcessDTO.setTemplateId(templateId);
            } else {
                startProcessDTO.setTemplateId(paasProcessTemplateList.get(0).getId());
            }
            params.remove("enable");
            params.put("templateId", startProcessDTO.getTemplateId());
            params.put("type", NodeTypeEnum.START_PROCESS_NODE.getNodeType());
            List<PaasProcessTemplateNodeEntityExt> startNodeList = processTemplateNodeModel.list(params);
            if (startNodeList == null || startNodeList.size() == 0) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PROCESS_NODE_TASK_NOT_EXIST);
            }
            PaasProcessTemplateNodeEntityExt templateNodeEntityExt = startNodeList.get(0);
            processNodeTaskUpdateDTO.setProcessTemplateNode(templateNodeEntityExt);
            startProcessDTO.setTemplateNode(templateNodeEntityExt);
            // 流程数据dto
            ProcessDataAddDTO processDataAddDTO = new ProcessDataAddDTO();
            BeanUtil.copyProperties(startProcessDTO, processDataAddDTO, true);
            processDataAddDTO.setTaskId(processNodeTaskUpdateDTO.getProcessTaskId());
            if (Objects.nonNull(startProcessDTO.getFormDataId())) {
                processDataAddDTO.setFormDataId(startProcessDTO.getFormDataId());
            }
            processDataAddDTO.setTemplateId(startProcessDTO.getTemplateId());
            processDataAddDTO.setData(startProcessDTO.getData());

            // 生成开始节点任务
            paasProcessOperateService.createStartNodeTask(startProcessDTO, templateNodeEntityExt, processDataAddDTO.getTaskId());
            StartProcessVO startProcessVO = paasProcessOperateService.deliverToNextNode(templateNodeEntityExt, processDataAddDTO);

            // 更新流程状态和流程负责人
            if (Objects.equals(startProcessVO.getNoApprovalRequired(), BasicConstant.ONE)) {
                // 如果目标节点为结束节点，则流程通过
                processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.PASS.getType());
            } else if (Objects.equals(startProcessVO.getNoApprovalRequired(), BasicConstant.TWO)) {
                processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.REJECT.getType());
            } else {
                // 将流程节点置为进行中
                processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.APPROVAL_PENDING.getType());
            }
            /*boolean isNeedApprove = paasProcessOperateService.isNeedApprove(templateNodeEntityExt, processDataAddDTO);
            // 重新提交任务时，将列表页的数据隐藏
            if (isNeedApprove) {
                paasProcessOperateService.createNodeTask(startProcessDTO, templateNodeEntityExt, processDataAddDTO);
                processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.APPROVAL_PENDING.getType());
            } else {
                processNodeTaskUpdateDTO.setFlowStatus(FlowStatusEnum.PASS.getType());
            }*/
            // 更新流程状态和流程数据
            processOperateHelp.updateProcessType(processNodeTaskUpdateDTO);
            processOperateHelp.updateProcessData(processNodeTaskUpdateDTO);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("PaasProcessNodeTask数据库流程重新提交操作出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return processNodeTaskUpdateVO;
    }

}
